/**
  ******************************************************************************
  * @file    usart3.c
  * @author  
  * @version 
  * @date    
  * @brief   
  ******************************************************************************
  * @attention
  *   usart3用于计量芯片串口通讯
  *   PB10-TX,PB11-RX
  ******************************************************************************
  */
  
#include "DRV_Usart3.h"

static uint8_t dma_tx_buf[USART3_DMA_BUF_LEN];
static uint8_t dma_rx_buf[USART3_DMA_BUF_LEN];

static comRxCallback comRxCbkFun=NULL;

uint8_t usart3_mda_rx_len=0;

/*******************************************************************************
* Function Name  : usart3_config
* Description    : 
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
static void usart3_config(u32 baud)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef  NVIC_InitStructure;
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);   //使能UART3
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,  ENABLE);   //使能GPIOB
 
	//端口配置
	//PB10 -> USART3_TX
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;        //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	    //速度50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);

	//PB11 -> USART3_RX
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
   //USART3 初始化设置
	USART_DeInit(USART3);
	USART_InitStructure.USART_BaudRate            = baud;						    //波特率设置
	USART_InitStructure.USART_WordLength          = USART_WordLength_9b;		    //字长为8位数据格式
	USART_InitStructure.USART_StopBits            = USART_StopBits_1;			    //一个停止位
	USART_InitStructure.USART_Parity              = USART_Parity_Even;				//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件数据流控制
	USART_InitStructure.USART_Mode                = USART_Mode_Rx | USART_Mode_Tx;	//收发模式
	USART_Init(USART3, &USART_InitStructure); 						                //初始化串口
	
    //开中断
	USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);	//开空闲中断
	USART_ITConfig(USART3, USART_IT_ERR,  ENABLE);	//开错误中断

	//清标志位
	USART_ClearFlag(USART3, USART_FLAG_TC);
	USART_ClearFlag(USART3, USART_FLAG_RXNE);
	USART_ClearFlag(USART3, USART_FLAG_IDLE);
	USART_ClearFlag(USART3, USART_FLAG_ORE);
	
	USART_Cmd(USART3, ENABLE);  //使能串口

	//NVIC 配置
	NVIC_InitStructure.NVIC_IRQChannel                   = USART3_IRQn; //串口中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 6;	        //抢占优先级6
	NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;			//子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;	    //IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);								        //初始化VIC寄存器
}

/*******************************************************************************
* Function Name  : dma_usart3_recv_config
* Description    : 
* Input          : None
* Output         : None
* Return         : None
* 1. usart3-rx-mda1-ch3
*******************************************************************************/
static void dma_usart3_recv_config(void)
{
	DMA_InitTypeDef DMA_InitStructure;		
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	                            //DMA1时钟打开
	
	DMA_DeInit(DMA1_Channel3); 
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&USART3->DR);		        //DR 寄存器地址 (0x40013804)
	DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)dma_rx_buf;	            //DMA接收缓冲地址
	DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;			    //外设->内存
	DMA_InitStructure.DMA_BufferSize         = USART3_DMA_BUF_LEN;		            //DMA缓冲大小
	DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;		    //dma 不自增
	DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;		        //内存自增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;	        //DMA 数据宽度
	DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;			    //DMA 内存宽度
	DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;				        //DMA 普通模式，不循环接收数据
	DMA_InitStructure.DMA_Priority           = DMA_Priority_High;                   //DMA 高优先级
	DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;				        //关闭内存到内存
	DMA_Init(DMA1_Channel3, &DMA_InitStructure);
	
	DMA_ClearFlag(DMA1_FLAG_GL3);                   //清除DMA1所有标志
	USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);	//开串口DMA1功能
	DMA_Cmd(DMA1_Channel3, ENABLE);					//开DMA1_3通道
}

/*******************************************************************************
* Function Name  : dma_usart3_send_config
* Description    : 
* Input          : None
* Output         : None
* Return         : None
* 1. usart3-tx-mda1-ch2
*******************************************************************************/
static void dma_usart3_send_config(void)
{
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);	                                //DMA1 时钟

	DMA_DeInit(DMA1_Channel2);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr     = (uint32_t)dma_tx_buf;   
	DMA_InitStructure.DMA_BufferSize         = 0;							            //DMA缓冲大小
	DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralDST;	                //内存到外设
	DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;               //DMA外设地址不自增
	DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;	                //DMA内存地址自增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;             //外设数据宽度
	DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;	                //DMA内存数据宽度
	DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;			                //不循环接收
	DMA_InitStructure.DMA_Priority           = DMA_Priority_VeryHigh;	                //高优先级
	DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;			                //关闭内存到内存模式
	DMA_Init(DMA1_Channel2, &DMA_InitStructure);
	
	DMA_ClearFlag(DMA1_FLAG_GL2);
	USART_DMACmd(USART3, USART_DMAReq_Tx, ENABLE);
	DMA_Cmd(DMA1_Channel2, DISABLE);
	
	//清除标志
	DMA_ClearFlag(DMA1_FLAG_GL2);
	DMA_ClearFlag(DMA1_FLAG_HT2);
	DMA_ClearFlag(DMA1_FLAG_TC2);
	DMA_ClearFlag(DMA1_FLAG_TE2);
}


/*******************************************************************************
* Function Name  : USART3_IRQHandler
* Description    : 
* Input          : None
* Output         : None
* Return         : None
* 1. usart3-tx-mda1-ch2
*******************************************************************************/
void USART3_IRQHandler(void)
{
	uint32_t  sr;
	sr = sr;
	
	if(USART_GetITStatus(USART3, USART_IT_TXE) != RESET)     //发送空
	{
		USART_ClearITPendingBit(USART3, USART_IT_TXE);
	}

	if(USART_GetITStatus(USART3, USART_IT_TC) != RESET)      //发送完成
	{
		USART_ClearITPendingBit(USART3, USART_IT_TC);
		USART_ITConfig(USART3, USART_IT_TC, DISABLE);                                  
	}
	
	if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)       //收到
	{	 	
		USART_ClearITPendingBit(USART3, USART_IT_RXNE);         //清接收中断标志
	}
	
	if(USART_GetITStatus(USART3, USART_IT_ORE) != RESET)        //溢出错误（移位寄存器中的数据需要转移到RDR中，但是RDR 中有数据未读）
	{
		sr = USART_ReceiveData(USART3);
		USART_ClearITPendingBit(USART3, USART_IT_ORE);
	}
	
	if(USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)       //空闲
	{
		sr = USART_ReceiveData(USART3);					        //读一次RDR数据
		DMA_Cmd(DMA1_Channel3, DISABLE);				        //关DMA接收通道
		USART_ClearITPendingBit(USART3, USART_IT_IDLE );        //清空闲中断
		
        usart3_mda_rx_len = USART3_DMA_BUF_LEN -DMA_GetCurrDataCounter(DMA1_Channel3);
        if(comRxCbkFun!=NULL) comRxCbkFun(dma_rx_buf, usart3_mda_rx_len);
		DMA1_Channel3->CMAR  = (uint32_t)dma_rx_buf;
		DMA1_Channel3->CNDTR = USART3_DMA_BUF_LEN;				
		DMA_Cmd(DMA1_Channel3, ENABLE);
	}

	if(USART_GetITStatus(USART3 ,USART_IT_PE | USART_IT_FE | USART_IT_NE) != RESET)//错误
	{
		sr = USART_ReceiveData(USART3);
		USART_ClearITPendingBit(USART3, USART_IT_PE | USART_IT_FE | USART_IT_NE);
	}
}

uint8_t uart3_dma_send(uint8_t *p_txbuf, uint32_t tx_len, comRxCallback cbk)
{	
    if(p_txbuf==NULL)
    {
        return FALSE;
    }
    
    if(cbk!=NULL)
    {
        comRxCbkFun = cbk;
    }
    
	//清标志位
	DMA_ClearFlag(DMA1_FLAG_TC2);               //传输完成中断
	DMA_ClearFlag(DMA1_FLAG_TE2);               //传输错误中断
	
	DMA_Cmd(DMA1_Channel2, DISABLE);	        //关DMA，重设置参数
	DMA1_Channel2->CMAR  = (u32)(p_txbuf);		//内存地址
	DMA1_Channel2->CNDTR = tx_len;				//重置"DMA"发送长度
	DMA_Cmd(DMA1_Channel2, ENABLE);	            //开始发送，执行此指令后CRR的EN位置1
    
	return TRUE;
}

void usart3_init(void)
{
    usart3_config(4800);
    dma_usart3_send_config();
    dma_usart3_recv_config();
}
